package com.cml.domain.service;

import com.cml.common.config.Configuration;
import com.cml.common.constant.NodeStatus;
import com.cml.domain.entity.ServerNode;
import com.cml.domain.entity.VoteMessage;
import com.cml.infrastructure.MessageQueueManager;
import com.cml.infrastructure.NetworkManager;
import com.cml.infrastructure.ServerReadIoThread;
import org.apache.log4j.Logger;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 姓名：陈茂林
 * 时间：2023/10/9 13:58
 * 描述：
 */
public class LeaderVoteService {
    private NetworkManager networkManager;

    //投票次数
    private Integer voteCount=0;

    private VoteMessage curVoteMessage = null;
    Map<Integer,List<VoteMessage>>  voteContainer = new HashMap<>();
    private Configuration configuration=Configuration.getInstance();

    Logger logger = Logger.getLogger(ServerReadIoThread.class);
    public LeaderVoteService(NetworkManager networkManager){
        this.networkManager = networkManager;
    }

    private ServerNode findAllFollowerServerNodeLeadar(List<ServerNode> allFollowerServerNode){
        for(ServerNode serverNode:allFollowerServerNode){
            if(serverNode.isLeader()){
                return serverNode;
            }
        }
        return null;
    }

    /**
     * leader选举
     * @return
     */
    public Integer leaderElect(){
        List<ServerNode> allFollowerServerNode = this.networkManager.getRemoteServerNodeManager().getAllFollowerServerNode();
        logger.info("当前follower节点数为："+allFollowerServerNode.size());
        //如果一个候选节点直接返回
        if(allFollowerServerNode.size() == 1){
            return allFollowerServerNode.get(0).getId();
        }
        //如果断开重连情况，不在重选leader
        ServerNode followerServerNodeLeadar=findAllFollowerServerNodeLeadar(allFollowerServerNode);
        if (followerServerNodeLeadar != null){
            NodeStatus.getInstance().setCurStatus(NodeStatus.NODE_HA);
            return followerServerNodeLeadar.getId();
        }
        startCurServerNodeVote(allFollowerServerNode,this.configuration.getNodeServerId(),this.configuration.getNodeServerId());

        Integer allFollowerServerNum=this.configuration.getNodeFollowerServerList().size();
        //大于节点半数
        int quorun = allFollowerServerNum /2 +1;
        while (true){
            try {
                VoteMessage voteMessage = (VoteMessage) MessageQueueManager.takeVoteMessage();
                logger.info("收到节点:"+voteMessage.getVoteNodeId() +"，第"+voteMessage.getVoteCount()+"轮投票："+voteMessage.getVoteNumber());
                if(voteCount == voteMessage.getVoteCount()){//同一轮投票
                    //其它节点投票大于当前的票号
                    if(this.curVoteMessage.getVoteNumber() < voteMessage.getVoteNumber()){
                        this.curVoteMessage=voteMessage;//设置最新的投票
                    }
                }else if(voteMessage.getVoteCount()> voteCount){//当前轮次已经过时
                    //设置最新的投票轮次
                    this.voteCount = voteMessage.getVoteCount();
                    this.curVoteMessage=voteMessage;
                }



                voteContainerManger(voteMessage.getVoteCount(),voteMessage);
                List<VoteMessage> curCountVoteList = voteContainer.get(curVoteMessage.getVoteCount());
                //开始汇票
                if(quorun <= curCountVoteList.size()){
                    logger.info("超过半数投票，开始进行汇票计算！");
                    Integer leader = mathVoteLeader(curCountVoteList,quorun);
                    if(leader != null){
                        logger.info("当前leader为："+leader);
                        return  leader;
                    }
                }

                //allFollowerServerNum要减掉自己
                if(allFollowerServerNum == curCountVoteList.size()){
                    startCurServerNodeVote(allFollowerServerNode,this.curVoteMessage.getVoteNumber(),this.configuration.getNodeServerId());
                }

            } catch (InterruptedException e) {
                logger.error(e);
                NodeStatus.getInstance().setCurStatus(NodeStatus.NODE_FAIL);
                break;
            }
        }
        return null;
    }

    private Integer mathVoteLeader(List<VoteMessage> curCountVoteList,int quorun){
        Map<Integer,Integer> countVoteNum= new HashMap();
        for (VoteMessage voteMessage : curCountVoteList){
            Integer serverNodeVoteNumber = countVoteNum.get(voteMessage.getVoteNumber());
            if (serverNodeVoteNumber == null){
                serverNodeVoteNumber=1;
            }else{
                serverNodeVoteNumber++;
            }
            countVoteNum.put(voteMessage.getVoteNumber(),serverNodeVoteNumber);
        }
        Integer maxVote = null;
        for(Integer item : countVoteNum.keySet()){
            if(countVoteNum.get(item) >= quorun){
                if(maxVote == null){
                    maxVote=item;
                }else{//多个投票大于一半，需重新投票
                    return null;
                }
            }
        }

        return maxVote;
    }

    private  void startCurServerNodeVote(List<ServerNode> allFollowerServerNode,Integer voteNumber,Integer voteNodeId){
        this.voteCount++;
        logger.info("------------------------------------");
        logger.info("开启第"+voteCount+"投票！");
        logger.info("------------------------------------");
        VoteMessage voteMessage = new VoteMessage();
        voteMessage.setVoteCount(this.voteCount);
        voteMessage.setVoteNumber(voteNumber);
        voteMessage.setVoteNodeId(voteNodeId);
        this.curVoteMessage = voteMessage;
        for(ServerNode remoteServerNode : allFollowerServerNode){
            try {
                if(this.configuration.getNodeServerId().equals(remoteServerNode.getId())){
                    //自己节点不做处理
                    continue;
                }
                logger.info("当前节点："+this.curVoteMessage.getVoteNodeId() +"，第"+this.curVoteMessage.getVoteCount()+"轮投票到："+remoteServerNode.getId()+"节点，投票为："+this.curVoteMessage.getVoteNumber());
                MessageQueueManager.sendMessage(remoteServerNode.getId(),this.curVoteMessage);
            } catch (Exception e) {
                logger.error(e);
                logger.error("节点："+remoteServerNode.getId()+"发起投票失败");
                NodeStatus.getInstance().setCurStatus(NodeStatus.NODE_FAIL);
                break;
            }
        }
        voteContainerManger(voteCount,curVoteMessage);

    }

    private  void voteContainerManger(int voteCount,VoteMessage voteMessage){
        List<VoteMessage> curCountVoteList = voteContainer.get(voteCount);
        //新的一轮投票
        if(curCountVoteList == null){
            voteContainer = new HashMap<>();
            curCountVoteList = new ArrayList<>();
            voteContainer.put(voteCount,curCountVoteList);
        }
        curCountVoteList.add(voteMessage);
    }



}
